﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;

#endregion

namespace ScrumTable.Common.Collections
{
    /// <summary>
    /// Contains the global utilities for the IEnumerable class.
    /// </summary>
    public static class EnumerableUtil
    {
        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the second element of the iterator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static T Second<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");
            return input.ElementAt(1);
        }

        /// <summary>
        /// Gets the second element of the iterator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static T SecondOrDefault<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");
            return input.ElementAtOrDefault(1);
        }

        /// <summary>
        /// Gets the third element of the iterator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static T Third<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");
            return input.ElementAt(2);
        }

        /// <summary>
        /// Gets the third element of the iterator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static T ThirdOrDefault<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");
            return input.ElementAtOrDefault(2);
        }

        /// <summary>
        /// Gets the fourth element of the iterator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static T Fourth<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");
            return input.ElementAt(3);
        }

        /// <summary>
        /// Gets the fourth element of the iterator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static T FourthOrDefault<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");
            return input.ElementAtOrDefault(3);
        }

        /// <summary>
        /// Returns true if the current enumerable object is empty.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static IEnumerable<T> ToEnumerable<T>(this IEnumerable input)
        {
            PreCondition.AssertNotNull(input, "input");
            return new TypedEnumerable<T>(input);
        }

        /// <summary>
        /// Returns true if the current enumerable object is empty.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static IEnumerable<object> ToEnumerable(this IEnumerable input)
        {
            PreCondition.AssertNotNull(input, "input");
            return new TypedEnumerable<object>(input);
        }

        /// <summary>
        /// Loops through all elements of the current enumerable instance.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEach<T>(this IEnumerable input, Action<T> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            foreach (T data in input)
            {
                doForEach(data);
            }
            return input.ToEnumerable<T>();
        }

        /// <summary>
        /// Loops through all elements of the current enumerable instance.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> input, Action<T> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            foreach (T data in input)
            {
                doForEach(data);
            }
            return input;
        }

        /// <summary>
        /// Loops through all elements of the current enumerable instance and passes through
        /// the current element index.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEachIndex<T>(this IEnumerable<T> input, Action<int> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            int count = input.Count();
            for (int i = 0; i < count; ++i)
            {
                doForEach(i);
            }
            return input;
        }

        /// <summary>
        /// Loops through all elements of the current enumerable instance and passes through
        /// the current element index.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEachIndex<T>(this IEnumerable<T> input, Action<int, T> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            int count = 0;
            foreach (T data in input)
            {
                doForEach(count, data);
                ++count;
            }
            return input;
        }

        /// <summary>
        /// Loops in a reverse manner through all elementsof the current enumerable instance
        /// and passes through the current element an index.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEachIndexReverse<T>(this IEnumerable<T> input, Action<int> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            for (int i = input.Count() - 1; i > -1; --i)
            {
                doForEach(i);
            }
            return input;
        }

        /// <summary>
        /// Loops in a reverse manner through all elementsof the current enumerable instance
        /// and passes through the current element an index.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEachReverse<T>(this IEnumerable<T> input, Action<T> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            IList<T> toLoopThrough = (input is IList<T>) ? (IList<T>) input : input.ToList();

            for (int i = toLoopThrough.Count; i > - 1; --i)
            {
                doForEach(toLoopThrough[i]);
            }
            return input;
        }

        /// <summary>
        /// Loops in a reverse manner through all elementsof the current enumerable instance
        /// and passes through the current element an index.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="doForEach">Action to call for each element.</param>
        /// <returns>Return input enumerable for chaining purposes.</returns>
        [DebuggerHidden]
        [DebuggerNonUserCode]
        public static IEnumerable<T> ForEachIndexReverse<T>(this IEnumerable<T> input, Action<T> doForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(doForEach, "doForEach");

            IList<T> loopProvider;

            // optimization: do not copy list entries of the given input is already a list
            if (typeof(IList<T>).IsAssignableFrom(typeof(IEnumerable<T>)))
            {
                loopProvider = (IList<T>) input;
            }
            else
            {
                loopProvider = input.ToList();
            }

            for (int i = loopProvider.Count - 1; i > -1; --i)
            {
                doForEach(loopProvider[i]);
            }
            return input;
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other list.
        /// </summary>
        /// <typeparam name="TOut">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static ICollection<TOut> Convert<TOut>(this IEnumerable input)
        {
            return Convert(input, data => data.ChangeType<TOut>());
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other list.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IList<T> Convert<T>(this IEnumerable input, Func<object, T> convertForEach)
        {
            return ConvertIf(input, data => true, convertForEach);
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other list.
        /// </summary>
        /// <typeparam name="TOut">Specifies the type of elements in the list.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IList<TOut> Convert<TOut, TIn>(this IEnumerable<TIn> input, Func<TIn, TOut> convertForEach)
        {
            return ConvertIf(input, data => true, convertForEach);
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other list.
        /// </summary>
        /// <typeparam name="TOut">Specifies the type of elements in the list.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IList<TOut> Convert<TOut, TIn>(this IEnumerable input, Func<TIn, TOut> convertForEach)
        {
            return ConvertIf(input, data => true, convertForEach);
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts each
        /// element to another if the condition to compare is true.
        /// </summary>
        /// <typeparam name="TOut">Specifies the type of elements in the list.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the list.</typeparam>
        /// <param name="toCompare">Specifies the comperator instance.</param>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IList<TOut> ConvertIf<TOut, TIn>(this IEnumerable<TIn> input, Predicate<TIn> toCompare, Func<TIn, TOut> convertForEach)
        {
            return ConvertIf(input as IEnumerable, toCompare, convertForEach);
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts eache
        /// element to another if the condition to compare is true.
        /// </summary>
        /// <typeparam name="TOut">Specifies the type of elements in the list.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the list.</typeparam>
        /// <param name="toCompare">Specifies the comperator instance.</param>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IList<TOut> ConvertIf<TOut, TIn>(this IEnumerable input, Predicate<TIn> toCompare, Func<TIn, TOut> convertForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(toCompare, "toCompare");
            PreCondition.AssertNotNull(convertForEach, "convertForEach");

            List<TOut> convertedData;
            if (input is ICollection) { convertedData = new List<TOut>(((ICollection)input).Count); }
            else { convertedData = new List<TOut>(); }

            foreach (TIn data in input)
            {
                if (toCompare(data))
                {
                    convertedData.Add(convertForEach(data));
                }
            }
            return convertedData;
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other dictionary if the condition returned true.
        /// </summary>
        /// <typeparam name="TKey">Specifies the type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">Specifies the type of elements in the dictionary.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the dictionary.</typeparam>
        /// <param name="toCompare">Specifies the comperator instance.</param>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IDictionary<TKey, TValue> ConvertIf<TKey, TValue, TIn>(this IEnumerable<TIn> input, Predicate<TIn> toCompare, Func<TIn, KeyValuePair<TKey, TValue>> convertForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(toCompare, "toCompare");
            PreCondition.AssertNotNull(convertForEach, "convertForEach");

            IDictionary<TKey, TValue> convertedData;
            if (input is ICollection<TIn>) { convertedData = new Dictionary<TKey, TValue>(((ICollection<TIn>)input).Count); }
            else { convertedData = new Dictionary<TKey, TValue>(); }

            foreach (TIn data in input)
            {
                if (toCompare(data))
                {
                    convertedData.Add(convertForEach(data));
                }
            }
            return convertedData;
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other dictionary.
        /// </summary>
        /// <typeparam name="TKey">Specifies the type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">Specifies the type of elements in the dictionary.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the dictionary.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IDictionary<TKey, TValue> Convert<TKey, TValue, TIn>(this IEnumerable<TIn> input, Func<TIn, KeyValuePair<TKey, TValue>> convertForEach)
        {
            return ConvertIf(input, data => true, convertForEach);
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other dictionary.
        /// </summary>
        /// <typeparam name="TKey">Specifies the type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">Specifies the type of elements in the dictionary.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static IDictionary<TKey, TValue> Convert<TKey, TValue>(this IEnumerable input, Func<object, KeyValuePair<TKey, TValue>> convertForEach)
        {
            return Convert(input.ToEnumerable(), convertForEach);
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and converts it into an
        /// other list.
        /// </summary>
        /// <typeparam name="TOut">Specifies the type of elements in the list.</typeparam>
        /// <typeparam name="TIn">Specifies the type of input elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="convertForEach">Action to call for each element.</param>
        public static ICollection<TOut> ConvertWithIndex<TOut, TIn>(this IEnumerable<TIn> input, Func<TIn, int, TOut> convertForEach)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(convertForEach, "convertForEach");

            List<TOut> convertedData = new List<TOut>();
            int index = 0;

            foreach (TIn data in input)
            {
                convertedData.Add(convertForEach(data, index));
                index++;
            }
            return convertedData;
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and calls the ToString()
        /// method of each element in order to join their values to a whole string.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="separator">Specifies the separator string.</param>
        public static string ToString<T>(this IEnumerable<T> input, string separator)
        {
            PreCondition.AssertNotNull(input, "input");

            StringBuilder builder = new StringBuilder();

            input.ForEach(
                element =>
                    {
                        if (builder.Length != 0)
                        {
                            builder.Append(separator);
                        }
                        builder.Append(element.ToString());
                    } );
            return builder.ToString();
        }

        /// <summary>
        /// Loops through all elements of the given enumerable instance and calls the ToString()
        /// method of each element in order to join their values to a whole string. The given
        /// selected value will be highlighted with parantheses ().
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="toHighlight">Specifies the element which should be highlighted with parantheses ().</param>
        /// <param name="separator">Specifies the separator string.</param>
        public static string ToString<T>(this IEnumerable<T> input, T toHighlight, string separator)
        {
            PreCondition.AssertNotNull(input, "input");

            StringBuilder builder = new StringBuilder();

            input.ForEach(
                element =>
                {
                    if (builder.Length != 0)
                    {
                        builder.Append(separator);
                    }
                    if (Equals(toHighlight, element))
                    {
                        builder.Append("(");
                    }
                    builder.Append(element.ToString());

                    if (Equals(toHighlight, element))
                    {
                        builder.Append(")");
                    }
                });
            return builder.ToString();
        }

        /// <summary>
        /// Converts the current IEnumerable into an array.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <typeparam name="TOut">Specifies the type of the output array.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="converter">Specifies the source (input) enumeration.</param>
        public static TOut[] ToArray<T, TOut>(this IEnumerable<T> input, Func<T, TOut> converter)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(converter, "converter");
            
            return input.Convert(converter).ToArray();
        }

        /// <summary>
        /// Returns true if the current enumerable contains an element which returned true when executing the given action.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="toEvaluateElement">Specifies the predicate to evaluate the element.</param>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static bool Contains<T>(this IEnumerable<T> input, Predicate<T> toEvaluateElement)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(toEvaluateElement, "toEvaluateElement");

            return !(from element in input
                     where toEvaluateElement(element)
                     select element).IsEmpty();
        }

        /// <summary>
        /// Returns true if the current enumerable object is empty.
        /// </summary>
        /// <typeparam name="T">Specifies the type of elements in the list.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static bool IsEmpty<T>(this IEnumerable<T> input)
        {
            PreCondition.AssertNotNull(input, "input");

            return IsEmpty((IEnumerable)input);
        }

        /// <summary>
        /// Returns true if the current enumerable object is empty.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        public static bool IsEmpty(this IEnumerable input)
        {
            PreCondition.AssertNotNull(input, "input");

            return !input.GetEnumerator().MoveNext();
        }

        /// <summary>
        /// Returns the index of an object.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="toCompare">Specifies the item to compare.</param>
        public static int GetIndex(this IEnumerable input, object toCompare)
        {
            PreCondition.AssertNotNull(input, "input");

            int i = -1;
            foreach (var obj in input)
            {
                i++;
                if (obj == toCompare || obj.Equals(toCompare)) return i;
            }
            return -1;
        }

        /// <summary>
        /// Returns the index of an object which is evaluted in conjunction with
        /// the given comperator.
        /// </summary>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <param name="comperator">Specifies the comperator to evaluate the index.</param>
        public static int GetIndex<T>(this IEnumerable<T> input, Predicate<T> comperator)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(comperator, "comperator");

            int i = -1;
            foreach (var obj in input)
            {
                i++;
                if (comperator(obj)) return i;
            }
            return -1;
        }

        /// <summary>
        /// Converts the given input enumerable into a sorted list which is optimized
        /// for searching.
        /// </summary>
        /// <typeparam name="T">Specifies the type of the list to create.</typeparam>
        /// <param name="input">Specifies the source (input) enumeration.</param>
        /// <returns>Returns the created sorted list.</returns>
        public static IDictionary<T, T> ToSortedList<T>(this IEnumerable<T> input)
        {
            SortedList<T, T> list;

            if (input is ICollection<T>)
            {
                list = new SortedList<T, T>(((ICollection<T>)input).Count);
            }
            else
            {
                list = new SortedList<T, T>(input.Count());
            }

            foreach (T toAdd in input)
            {
                list[toAdd] = toAdd;
            }
            return list;
        }


        /// <summary>
        /// Filters all the same elements from the both enumerables and returns only
        /// the distinct elements.
        /// </summary>
        /// <example>
        /// <code>
        /// input  |  toCompare  =  result
        ///   a    |    a             b
        ///   b    |    c             d
        ///   c    |    d
        /// </code>
        /// </example>
        /// <typeparam name="T">Specifies the type of the enumerable elements to compare.</typeparam>
        /// <param name="input">Defines the input (this-ptr) element of the first input sequence.</param>
        /// <param name="toCompare">Defines the input (this-ptr) element of the second input sequence.</param>
        public static IEnumerable<T> DistinctElements<T>(this IEnumerable<T> input, IEnumerable<T> toCompare)
        {
            PreCondition.AssertNotNull(input, "input");
            PreCondition.AssertNotNull(toCompare, "toCompare");

            IDictionary<T, T> result = new SortedList<T, T>();
            IDictionary<T, T> inputOpt = input.ToSortedList();
            IDictionary<T, T> toCompareOpt = toCompare.ToSortedList();

            foreach (var elementInInputPair in inputOpt)
            {
                var elementInInput = elementInInputPair.Key;

                if (!toCompareOpt.ContainsKey(elementInInput))
                {
                    result[elementInInput] = elementInInput;
                }
            }

            if (inputOpt.Count != toCompareOpt.Count)
            {
                foreach (var elementInToComparePair in toCompareOpt)
                {
                    var elementInToCompare = elementInToComparePair.Key;

                    if (!inputOpt.ContainsKey(elementInToCompare))
                    {
                        result[elementInToCompare] = elementInToCompare;
                    }
                }
            }
            return result.Keys;
        }

        /// <summary>
        /// Returns true if there are distinct elements in the sequences.
        /// For more information see <see cref="DistinctElements{T}"/>.
        /// </summary>
        /// <typeparam name="T">Specifies the type of the enumerable elements to compare.</typeparam>
        /// <param name="input">Defines the input (this-ptr) element of the first input sequence.</param>
        /// <param name="toCompare">Defines the input (this-ptr) element of the second input sequence.</param>
        public static bool HasDistinctElements<T>(this IEnumerable<T> input, IEnumerable<T> toCompare)
        {
            return (DistinctElements(input, toCompare).Count() != 0);
        }

        #endregion
    }
}
